package data;

import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.util.Log;

import junit.framework.Assert;

import org.apache.http.NameValuePair;
import org.apache.http.message.BasicNameValuePair;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;

import util.http.HttpGetConnector;

/**
 * 사용자에 대한 정보를 가지는 싱글턴 클래스
 */
public class Users
{
	private static final String LOG_TAG = "WAFortplio_data.Users";
	private static final String PREF_NAME = "Users";
	private static Users instance; // 싱글톤 인스턴스

	private Context context;

	// 오류코드에 대한 내용
	public static final int NO_ERROR = 0; // 오류없음
	public static final int UNCORRECT_DATA = 1; // 잘못된 아이디나 비밀번호가 입력됨
	public static final int UNCORRECT_CONFIRM = 3; // 비밀번호와 비밀번호 확인이 일치하지 않음
	public static final int DUPLICATED_ID = 4; // 중복된 아이디가 입력됨
	public static final int FORBIDDEN = 6; // 잘못된 접근 (매개변수 전달 안함)

	// 로그인에 필요한 데이터
	private String id;       // 사용자 아이디
	private String password; // 사용자 비밀번호

	// 사용자 정보
	private int num;      // 사용자 번호
	private String name;     // 사용자 이름
	private String birthday; // 사용자 생일

	// 프로필 정보
	private String profileContent;          // 프로필 내용
	private String coverstoryContent;       // 커버스토리 내용
	private NameValuePair[] profileCoulmns; // 프로필 자세한 내용

	// 프로필 사진
	private Bitmap profileImage;
	private Bitmap coverstoryImage;

	private DataReceiver listener;

	/**
	 * 서버로부터 데이터를 받았다는 신호를 받기위한 인터페이스
	 */
	public static interface DataReceiver
	{
		public void onDataReceived(String data, int errorCode);
	}

	/**
	 * 외부에서 객체생성을 하지 못하게 하기 위한 생성자
	 */
	private Users(Context context)
	{
		this.context = context;

		// 기기에 저장되어 있던 로그인 정보를 불러온다.
		loadLoginData();

		reload();
	}

	public void reload()
	{
		profileCoulmns = new NameValuePair[7];

		// 서버로부터 데이터를 가져온다.
		final Handler handler = new Handler(); // UI 스레드로 신호를 보내기 위한 핸들러
		new Thread()
		{
			@Override
			public void run()
			{
				try
				{
					HttpGetConnector connector = new HttpGetConnector("http://contest.iwop.net/2013/fortpolio/mobile_return_profile.php");
					Log.v(LOG_TAG, "id : " + id);
					String html = connector.request("email", id);
					Log.v(LOG_TAG, "서버에 퀴리 보낸 결과 : " + html);

					try
					{
						String[] datas = html.split("ꕤ");
						profileContent = datas[0];
						coverstoryContent = datas[1];
						String profileImagePath = datas[2];
						profileImage = getRemoteImage("http://contest.iwop.net/2013/fortpolio/" + profileImagePath);
						String coverstoryImagePath = datas[3];
						coverstoryImage = getRemoteImage("http://contest.iwop.net/2013/fortpolio/" + coverstoryImagePath);

						// 서버로부터 사용자 데이터 다 다운로드 받았다고 리스너에게 알린다.
						handler.post(new Runnable()
						{
							@Override
							public void run()
							{
								listener.onDataReceived(null, 0);
							}
						});
					}
					catch (ArrayIndexOutOfBoundsException e)
					{
					}
				}
				catch (IOException e)
				{
					e.printStackTrace();
				}
			}
		}.start();
	}

	/**
	 * 기기로부터 로그인에 필요한 정보(아이디와 비밀번호)를 불러오는 메서드
	 */
	private void loadLoginData()
	{
		SharedPreferences prefs = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
		id = prefs.getString("id", null);
		password = prefs.getString("password", null);
	}

	/**
	 * 기기에 저장된 로그인 정보를 지우는 메서드
	 */
	public void removeLoginData()
	{
		num = 0;
		name = null;
		birthday = null;

		profileContent = null;
		coverstoryContent = null;
		profileCoulmns = new NameValuePair[7];

		SharedPreferences prefs = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
		SharedPreferences.Editor editor = prefs.edit();
		editor.putString("id", null);
		editor.putString("password", null);
		editor.commit();
		loadLoginData();
	}

	public void saveLoginData(String id, String password)
	{
		SharedPreferences prefs = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
		SharedPreferences.Editor editor = prefs.edit();
		editor.putString("id", id);
		editor.putString("password", password);
		editor.commit();

		loadLoginData();
	}

	/**
	 * 기기에 사용자의 아이디와 비밀번호가 저장되어 있는지 확인하는 메서드
	 *
	 * @return : 저장되어 있으면 true 그렇지 않으면 false
	 */
	public boolean isLoginDataExist()
	{
		return id != null && password != null;
	}

	/**
	 * 서버로부터 데이터를 받아오는 메서드
	 *
	 * @param param    : 받아올 것의 이름
	 * @param table    : 테이블 이름
	 * @param receiver : 데이터를 받아왔다는 신호를 수신할 인터페이스
	 */
	private void retrieveData(final String param, final String table, final DataReceiver receiver)
	{
		final Handler handler = new Handler(); // UI 스레드로 신호를 보내기 위한 핸들러

		new Thread()
		{
			@Override
			public void run()
			{
				int errorCode = 0;
				String html = null;

				try
				{
					HttpGetConnector connector = new HttpGetConnector("http://contest.iwop.net/2013/fortpolio/mobile_member_retriever.php");
					html = connector.request(
							"email", id,
							"table", table,
							"value", param);
					errorCode = Integer.parseInt(html);

					// 이 아래 문장을 실행하면 오류가 있는 것이므로 데이터 리시버에 오류신호를 보낸다.
					final int code = errorCode;
					handler.post(new Runnable()
					{
						@Override
						public void run()
						{
							listener.onDataReceived(null, code);
						}
					});
				}

				// 에러코드가 없으면
				catch (NumberFormatException e)
				{
					// 데이터 리시버에 신호를 보낸다.
					final String result = (html == null) ? "" : html;
					handler.post(new Runnable()
					{
						@Override
						public void run()
						{
							receiver.onDataReceived(result, 0);
						}
					});
				}

				// 네트워크 예외가 발생했으면
				catch (IOException e)
				{
					Log.v(LOG_TAG, "네트워크 오류 발생!");
				}
			}
		}.start();
	}

	public void getName(final DataReceiver receiver)
	{
		if (name != null)
		{
			receiver.onDataReceived(name, 0);
			return;
		}

		retrieveData("name", "member", new DataReceiver()
		{
			@Override
			public void onDataReceived(String data, int errorCode)
			{
				Users.this.name = data;
				receiver.onDataReceived(data, errorCode);
			}
		});
	}

	public String getProfileContent()
	{
		return profileContent;
	}

	public String getCoverstoryContent()
	{
		return coverstoryContent;
	}

	/**
	 * 리스너를 설정하는 메서드
	 *
	 * @param listener : 리스너
	 */
	public void setListener(DataReceiver listener)
	{
		this.listener = listener;
	}

	public void getColumn(final int index, final DataReceiver receiver)
	{
		if (profileCoulmns[index] != null)
		{
			receiver.onDataReceived(profileCoulmns[index].getName() + "\n" +
					profileCoulmns[index].getValue(), 0);
			return;
		}

		retrieveData("column" + (index + 1), "profile", new DataReceiver()
		{
			@Override
			public void onDataReceived(String data, int errorCode)
			{
				String[] datas = data.split("\n");
				if (datas.length == 2)
					Users.this.profileCoulmns[index] = new BasicNameValuePair(datas[0], datas[1]);

				receiver.onDataReceived(data, errorCode);
			}
		});
	}

	public Bitmap getProfileImage()
	{
		return profileImage;
	}

	public Bitmap getCoverstoryImage()
	{
		return coverstoryImage;
	}

	public Bitmap getRemoteImage(String address)
	{
		URL url;
		InputStream is;
		try
		{
			url = new URL(address);
			is = (InputStream) url.getContent();
		}
		catch (Exception e)
		{
			e.printStackTrace();
			return null;
		}

		BitmapDrawable d = (BitmapDrawable) Drawable.createFromStream(is, "src");
		return d.getBitmap();
	}

	/**
	 * 싱글턴 객체를 생성하는 메서드
	 * 자동으로 로그인 데이터를 가져온다.
	 */
	public static void initialize(Context context)
	{
		instance = new Users(context);
	}

	/**
	 * 싱글턴 객체를 가져오는 메서드
	 * @return : 싱글턴 객체
	 */
	public static Users getInstance()
	{
		Assert.assertNotNull("사용자에 대한 정보 클래스가 초기화되지 않았습니다.", instance);
		return instance;
	}
}